#include "ButtonGroup.h"
#include <QLayout>
#include "../../Utility/XXlogger.h"

ButtonGroup::ButtonGroup(QObject *parent)
    : QObject(parent)
{
    _selectable = false;
    _exclusive = false;
    _canUnSelectWhenOnlyOne = false;
}

void ButtonGroup::shell(QWidget *container){
    _widget = container;

    QList<QAbstractButton*> buttons = _widget->findChildren<QAbstractButton*>(QString(),Qt::FindDirectChildrenOnly);
    foreach(QAbstractButton *button, buttons){
        button->setCheckable(_selectable);
        _nameToButton[button->objectName()] = button;
        connect(button,&QAbstractButton::clicked,this,&ButtonGroup::onButtonClicked);
    }
}

void ButtonGroup::setSelectable(bool selectable){
    _selectable = selectable;
    if(_nameToButton.empty()){
        return;
    }
    for (auto iter=_nameToButton.begin(); iter!=_nameToButton.end(); iter++) {
        iter.value()->setCheckable(selectable);
    }
}
void ButtonGroup::setExclusive(bool exclusive, bool canUnSelectWhenOnlyOne){
    _exclusive = exclusive;
    _canUnSelectWhenOnlyOne = canUnSelectWhenOnlyOne;
}

bool ButtonGroup::add(const QString &name, QAbstractButton *button){
    if(nullptr==_widget || nullptr==_widget->layout()){
        xxErr("could not add item when container is nullptr or layout is nullptr.");
        return false;
    }
    if(_nameToButton.contains(name)){
        //xxErrStrF(("name is exists. name:%1").arg(name));
        return false;
    }
    _nameToButton[name] = button;
    connect(button,&QAbstractButton::clicked,this,&ButtonGroup::onButtonClicked);
    button->setCheckable(_selectable);
    _widget->layout()->addWidget(button);
    return true;
}
void ButtonGroup::remove(const QString &name){
    if(!_nameToButton.contains(name)){
        xxErrStrF(("name is not exists. name:%1").arg(name));
        return;
    }
    QAbstractButton *button = _nameToButton.take(name);
    disconnect(button,&QAbstractButton::clicked,this,&ButtonGroup::onButtonClicked);
    removeFromCurrent(name);
}
void ButtonGroup::del(const QString &name){
    if(!_nameToButton.contains(name)){
        xxErrStrF(("name is not exists. name:%1").arg(name));
        return;
    }
    QAbstractButton *button = _nameToButton.take(name);
    disconnect(button,&QAbstractButton::clicked,this,&ButtonGroup::onButtonClicked);
    button->deleteLater();
    removeFromCurrent(name);
}
QAbstractButton* ButtonGroup::take(const QString &name){
    if(!_nameToButton.contains(name)){
        xxErrStrF(("name is not exists. name:%1").arg(name));
        return nullptr;
    }
    QAbstractButton *button = _nameToButton.take(name);
    disconnect(button,&QAbstractButton::clicked,this,&ButtonGroup::onButtonClicked);
    removeFromCurrent(name);
    return button;
}

void ButtonGroup::select(const QString &name){
    if(_exclusive){
        setCurrent(name);
    }
    else{
        addToCurrent(name);
    }
}
void ButtonGroup::unselect(const QString &name){
    removeFromCurrent(name);
}
QStringList ButtonGroup::currentSelected(){
    return _current;
}

void ButtonGroup::setCurrent(const QString &name){
    if(_current.contains(name) && _current.count()==1){
        return;
    }

    // [1] unselect current
    for (int index=0; index<_current.count(); index++) {
        QAbstractButton *button = _nameToButton.value(_current[index],nullptr);
        if(nullptr == button){
            xxErrStrF(("failure to find button with name. name:%1").arg(_current[index]));
            continue;
        }
        button->setChecked(false);
    }

    // [2] select new one
    QAbstractButton *button = _nameToButton.value(name,nullptr);
    if(nullptr == button){
        xxErrStrF(("failure to find button with name. name:%1").arg(name));
        return;
    }
    button->setChecked(true);

    // [3] modify property and emit signal
    QStringList last = _current;
    _current.clear();
    _current<<name;
    emit sigSelectionChanged(_current,last);
}
void ButtonGroup::addToCurrent(const QString &name){
    if(_current.contains(name)){
        return;
    }

    // [1] select new one
    QAbstractButton *button = _nameToButton.value(name,nullptr);
    if(nullptr == button){
        xxErrStrF(("failure to find button with name. name:%1").arg(name));
        return;
    }
    button->setChecked(true);

    // [2] modify property and emit signal
    QStringList last = _current;
    _current<<name;
    emit sigSelectionChanged(_current,last);
}
void ButtonGroup::removeFromCurrent(const QString &name){
    if(!_current.contains(name)){
        return;
    }

    // [1] unselect
    QAbstractButton *button = _nameToButton.value(name,nullptr);
    if(nullptr == button){
        xxErrStrF(("failure to find button with name. name:%1").arg(name));
        return;
    }
    button->setChecked(false);

    // [2] modify property and emit signal
    QStringList last = _current;
    _current.removeOne(name);
    emit sigSelectionChanged(_current,last);
}
QStringList ButtonGroup::getCurrent(){
    return _current;
}

void ButtonGroup::onButtonClicked(bool checked){
    QAbstractButton *button = qobject_cast<QAbstractButton*>(sender());
    QString name = _nameToButton.key(button,"");
    if(name.isEmpty()){
        xxErrStrF(("failure to find name with button. objectName:%1 text:%2").arg(button->objectName()).arg(button->text()));
    }

    if(_selectable){
        if(checked){
            if(_exclusive){
                setCurrent(name);
            }
            else{
                addToCurrent(name);
            }
        }
        else{
            if(!_canUnSelectWhenOnlyOne && getCurrent().count() == 1){
                button->setChecked(true);
            }
            else{
                removeFromCurrent(name);
            }
        }
    }
    else{
        emit sigClicked(_nameToButton.key(button));
    }
}

